Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/player.c | 319 +++++++++++++++++++++++++++++++++++++++++++------ dlls/wmp/wmp_private.h | 34 ++++++ 2 files changed, 317 insertions(+), 36 deletions(-)
diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index 69979be21d..268764955a 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -17,12 +17,14 @@ */
#include "wmp_private.h" +#include "wmpids.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(wmp);
-static void update_state(WindowsMediaPlayer *wmp, int state); +static void update_state(WindowsMediaPlayer *wmp, LONG type, LONG state); +static void media_change(WindowsMediaPlayer *wmp, LONG type, IDispatch *pItem);
static inline WindowsMediaPlayer *impl_from_IWMPNetwork(IWMPNetwork *iface) { @@ -44,6 +46,20 @@ static inline WindowsMediaPlayer *impl_from_IWMPControls(IWMPControls *iface) return CONTAINING_RECORD(iface, WindowsMediaPlayer, IWMPControls_iface); }
+HRESULT WINAPI WMPControls_play(IWMPControls *iface) +{ + HRESULT hres; + WindowsMediaPlayer *This = impl_from_IWMPControls(iface); + TRACE("(%p)\n", This); + hres = IMediaControl_Run(This->media_control); + if (SUCCEEDED(hres)) + { + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_PLAYING); + media_change(This, DISPID_WMPCOREEVENT_MEDIACHANGE, (IDispatch*)&This->IWMPMedia_iface); + } + return hres; +} + static HRESULT WINAPI WMPPlayer4_QueryInterface(IWMPPlayer4 *iface, REFIID riid, void **ppv) { WindowsMediaPlayer *This = impl_from_IWMPPlayer4(iface); @@ -111,9 +127,38 @@ static HRESULT WINAPI WMPPlayer4_get_URL(IWMPPlayer4 *iface, BSTR *pbstrURL)
static HRESULT WINAPI WMPPlayer4_put_URL(IWMPPlayer4 *iface, BSTR url) { + HRESULT hres; WindowsMediaPlayer *This = impl_from_IWMPPlayer4(iface); - FIXME("(%p)->(%s)\n", This, debugstr_w(url)); - return E_NOTIMPL; + TRACE("(%p)->(%s)\n", This, debugstr_w(url)); + if (!url) + return E_POINTER; + if (This->url) { + heap_free(This->url); + } + This->url = heap_strdupW(url); + + if (!This->url) + return E_OUTOFMEMORY; + + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_CHANGING); + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_TRANSITIONING); + media_change(This, DISPID_WMPCOREEVENT_CURRENTITEMCHANGE, (IDispatch*)&This->IWMPMedia_iface); + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_CHANGED); + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_PLAYLIST_OPEN_NO_MEDIA); + media_change(This, DISPID_WMPCOREEVENT_CURRENTITEMCHANGE, (IDispatch*)&This->IWMPMedia_iface); + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_OPENING_UNKNOWN_URL); + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_TRANSITIONING); + media_change(This, DISPID_WMPCOREEVENT_CURRENTITEMCHANGE, (IDispatch*)&This->IWMPMedia_iface); + + hres = IGraphBuilder_RenderFile(This->pFilterGraph, url, NULL); + if (SUCCEEDED(hres)) { + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, WMP_OPEN_STATE_MEDIA_OPEN); + } + + if (SUCCEEDED(hres) && This->autoStart) + WMPControls_play((IWMPControls*)This); + + return hres; }
static HRESULT WINAPI WMPPlayer4_get_openState(IWMPPlayer4 *iface, WMPOpenState *pwmpos) @@ -504,15 +549,19 @@ static HRESULT WINAPI WMPSettings_get_isAvailable(IWMPSettings *iface, BSTR item static HRESULT WINAPI WMPSettings_get_autoStart(IWMPSettings *iface, VARIANT_BOOL *p) { WindowsMediaPlayer *This = impl_from_IWMPSettings(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, p); + if (!p) + return E_POINTER; + *p = This->autoStart; + return S_OK; }
static HRESULT WINAPI WMPSettings_put_autoStart(IWMPSettings *iface, VARIANT_BOOL v) { WindowsMediaPlayer *This = impl_from_IWMPSettings(iface); - FIXME("(%p)->(%x)\n", This, v); - return E_NOTIMPL; + TRACE("(%p)->(%x)\n", This, v); + This->autoStart = v; + return S_OK; }
static HRESULT WINAPI WMPSettings_get_baseURL(IWMPSettings *iface, BSTR *p) @@ -546,15 +595,21 @@ static HRESULT WINAPI WMPSettings_put_defaultFrame(IWMPSettings *iface, BSTR v) static HRESULT WINAPI WMPSettings_get_invokeURLs(IWMPSettings *iface, VARIANT_BOOL *p) { WindowsMediaPlayer *This = impl_from_IWMPSettings(iface); + /* Leaving as FIXME as we don't currently use this */ FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + if (!p) + return E_POINTER; + *p = This->invokeURLs; + return S_OK; }
static HRESULT WINAPI WMPSettings_put_invokeURLs(IWMPSettings *iface, VARIANT_BOOL v) { WindowsMediaPlayer *This = impl_from_IWMPSettings(iface); + /* Leaving as FIXME as we don't currently use this */ FIXME("(%p)->(%x)\n", This, v); - return E_NOTIMPL; + This->invokeURLs = v; + return S_OK; }
static HRESULT WINAPI WMPSettings_get_mute(IWMPSettings *iface, VARIANT_BOOL *p) @@ -615,16 +670,26 @@ 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); + 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); + /* 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) @@ -644,15 +709,21 @@ static HRESULT WINAPI WMPSettings_setMode(IWMPSettings *iface, BSTR mode, VARIAN static HRESULT WINAPI WMPSettings_get_enableErrorDialogs(IWMPSettings *iface, VARIANT_BOOL *p) { WindowsMediaPlayer *This = impl_from_IWMPSettings(iface); + /* Leaving as FIXME as we don't currently use this */ FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + if (!p) + return E_POINTER; + *p = This->enableErrorDialogs; + return S_OK; }
static HRESULT WINAPI WMPSettings_put_enableErrorDialogs(IWMPSettings *iface, VARIANT_BOOL v) { WindowsMediaPlayer *This = impl_from_IWMPSettings(iface); + /* Leaving as FIXME as we don't currently use this */ FIXME("(%p)->(%x)\n", This, v); - return E_NOTIMPL; + This->enableErrorDialogs = v; + return S_OK; }
static const IWMPSettingsVtbl WMPSettingsVtbl = { @@ -689,9 +760,124 @@ static const IWMPSettingsVtbl WMPSettingsVtbl = { };
void destroy_player(WindowsMediaPlayer* wmp) { + /* shutdown event thread */ + if (wmp->event_thread) + { + SetEvent(wmp->stop_event); + WaitForSingleObject(wmp->event_thread, INFINITE); + CloseHandle(wmp->event_thread); + CloseHandle(wmp->stop_event); + } + + if (wmp->media_seeking) + IMediaSeeking_Release(wmp->media_seeking); + if (wmp->media_event) + IBasicAudio_Release(wmp->basic_audio); + if (wmp->media_event) + IMediaEvent_Release(wmp->media_event); + if (wmp->media_control) + IMediaControl_Release(wmp->media_control); + if (wmp->pFilterGraph) + IGraphBuilder_Release(wmp->pFilterGraph); + if (wmp->url) + heap_free(wmp->url); heap_free(wmp); }
+static void status_change(WindowsMediaPlayer *wmp) +{ + DISPPARAMS dispparams; + + dispparams.cArgs = 1; + dispparams.cNamedArgs = 0; + dispparams.rgdispidNamedArgs = NULL; + dispparams.rgvarg = NULL; + + call_sink(wmp->wmpocx, DISPID_WMPCOREEVENT_STATUSCHANGE, + &dispparams); +} + +static void media_change(WindowsMediaPlayer *wmp, LONG type, IDispatch *pItem) +{ + DISPPARAMS dispparams; + VARIANTARG params[1]; + + dispparams.cArgs = 1; + dispparams.cNamedArgs = 0; + dispparams.rgdispidNamedArgs = NULL; + dispparams.rgvarg = params; + + V_VT(params) = VT_DISPATCH; + V_DISPATCH(params) = pItem; + + call_sink(wmp->wmpocx, type, + &dispparams); + status_change(wmp); +} +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); + status_change(wmp); +} + +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); + media_change(wmp, DISPID_WMPCOREEVENT_MEDIACHANGE, (IDispatch*)&wmp->IWMPMedia_iface); + 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 { + TRACE("Unknown error (%d)\n", (int)r); + break; + } + } + + return ret; +} + + HRESULT WINAPI WMPControls_fastForward(IWMPControls *iface) { WindowsMediaPlayer *This = impl_from_IWMPControls(iface); @@ -723,8 +909,14 @@ HRESULT WINAPI WMPControls_get_currentMarker(IWMPControls *iface, LONG *plMarker 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); + hres = IMediaSeeking_GetCurrentPosition(This->media_seeking, ¤tPosition); + *pdCurrentPosition = (DOUBLE) currentPosition / 10000000.0f; + TRACE("hres: %d, pos: %f\n", hres, *pdCurrentPosition); + return hres; }
HRESULT WINAPI WMPControls_get_currentPositionString(IWMPControls *iface, BSTR *pbstrCurrentPosition) @@ -736,9 +928,22 @@ HRESULT WINAPI WMPControls_get_currentPositionString(IWMPControls *iface, BSTR *
static HRESULT WINAPI WMPControls_get_isAvailable(IWMPControls *iface, BSTR bstrItem, VARIANT_BOOL *pIsAvailable) { + HRESULT hres = E_NOTIMPL; 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); + if (strcmpW(currentPosition, bstrItem) == 0) { + DWORD capabilities; + hres = IMediaSeeking_GetCapabilities(This->media_seeking, &capabilities); + *pIsAvailable = (capabilities & AM_SEEKING_CanSeekAbsolute) ? + VARIANT_TRUE : VARIANT_FALSE; + } else { + FIXME("%s not implemented\n", debugstr_w(bstrItem)); + } + hres = S_OK; + *pIsAvailable = VARIANT_TRUE; + + return hres; }
HRESULT WINAPI WMPControls_next(IWMPControls *iface) @@ -755,13 +960,6 @@ HRESULT WINAPI WMPControls_pause(IWMPControls *iface) return E_NOTIMPL; }
-HRESULT WINAPI WMPControls_play(IWMPControls *iface) -{ - WindowsMediaPlayer *This = impl_from_IWMPControls(iface); - FIXME("(%p)\n", This); - return E_NOTIMPL; -} - HRESULT WINAPI WMPControls_playItem(IWMPControls *iface, IWMPMedia *pIWMPMedia) { WindowsMediaPlayer *This = impl_from_IWMPControls(iface); @@ -792,16 +990,27 @@ HRESULT WINAPI WMPControls_put_currentMarker(IWMPControls *iface, LONG lMarker)
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); + Current = 10000000 * dCurrentPosition; + hres = IMediaSeeking_SetPositions(This->media_seeking, &Current, + AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning); + + return hres; }
HRESULT WINAPI WMPControls_stop(IWMPControls *iface) { + HRESULT hres; WindowsMediaPlayer *This = impl_from_IWMPControls(iface); - FIXME("(%p)\n", This); - return E_NOTIMPL; + TRACE("(%p)\n", This); + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_TRANSITIONING); + hres = IMediaControl_Stop(This->media_control); + if (SUCCEEDED(hres)) + update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, WMP_PLAY_STATE_STOPPED); + return hres; }
static HRESULT WINAPI WMPControls_QueryInterface(IWMPControls *iface, REFIID riid, void **ppv) @@ -946,9 +1155,15 @@ HRESULT WINAPI WMPMedia_getMarkerName(IWMPMedia *iface, LONG MarkerNum, BSTR *pb
HRESULT WINAPI WMPMedia_get_duration(IWMPMedia *iface, DOUBLE *pDuration) { + LONGLONG duration; + HRESULT hres; WindowsMediaPlayer *This = impl_from_IWMPMedia(iface); - FIXME("(%p)->(%p)\n", This, pDuration); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, pDuration); + hres = IMediaSeeking_GetDuration(This->media_seeking, &duration); + if (SUCCEEDED(hres)) + *pDuration = (DOUBLE)duration / 10000000.0f; + TRACE("%d, %f, %lld\n", hres, *pDuration, duration); + return hres; }
HRESULT WINAPI WMPMedia_get_durationString(IWMPMedia *iface, BSTR *pbstrDuration) @@ -1189,8 +1404,9 @@ 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; + FIXME("stub, returning 100 (%p)->(%p)\n", This, plBufferingProgress); + *plBufferingProgress = 100; + return S_OK; }
static HRESULT WINAPI WMPNetwork_get_bufferingTime(IWMPNetwork *iface, LONG *plBufferingTime) @@ -1315,8 +1531,9 @@ 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; + FIXME("stub, returning 100 (%p)->(%p)\n", This, plDownloadProgress); + *plDownloadProgress = 100; + return S_OK; }
static HRESULT WINAPI WMPNetwork_get_encodedFrameRate(IWMPNetwork *iface, LONG *plFrameRate) @@ -1373,11 +1590,41 @@ static const IWMPNetworkVtbl WMPNetworkVtbl = {
HRESULT init_player(WindowsMediaPlayer *wmp) { + HRESULT hres; + wmp->IWMPPlayer4_iface.lpVtbl = &WMPPlayer4Vtbl; wmp->IWMPSettings_iface.lpVtbl = &WMPSettingsVtbl; wmp->IWMPControls_iface.lpVtbl = &WMPControlsVtbl; wmp->IWMPMedia_iface.lpVtbl = &WMPMediaVtbl; wmp->IWMPNetwork_iface.lpVtbl = &WMPNetworkVtbl;
+ wmp->invokeURLs = TRUE; + wmp->autoStart = TRUE; + + + hres = CoCreateInstance(&CLSID_FilterGraph, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IGraphBuilder, + (void **)&wmp->pFilterGraph); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(wmp->pFilterGraph, &IID_IMediaControl, (void**)&wmp->media_control); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(wmp->pFilterGraph, &IID_IMediaEvent, (void**)&wmp->media_event); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(wmp->pFilterGraph, &IID_IBasicAudio, (void**)&wmp->basic_audio); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(wmp->pFilterGraph, &IID_IMediaSeeking, (void**)&wmp->media_seeking); + if (SUCCEEDED(hres)) + hres = IMediaSeeking_SetTimeFormat(wmp->media_seeking, &TIME_FORMAT_MEDIA_TIME); + if (SUCCEEDED(hres)) + { + wmp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL); + wmp->event_thread = CreateThread(NULL, 0, WMP_event_thread, wmp, 0, NULL); + } + if (!wmp->event_thread) { + TRACE("Can't create thread\n"); + return E_FAIL; + } return S_OK; } diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index b9c66a952a..810fafaf27 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -22,6 +22,8 @@ #include "wine/heap.h" #include "ole2.h" #include "wmp.h" +#include "wine/unicode.h" +#include "dshow.h"
typedef struct { IConnectionPoint IConnectionPoint_iface; @@ -55,6 +57,23 @@ struct WindowsMediaPlayer { SIZEL extent;
ConnectionPoint *wmpocx; + + /* Settings */ + VARIANT_BOOL autoStart; + VARIANT_BOOL invokeURLs; + VARIANT_BOOL enableErrorDialogs; + BSTR url; + + /* DirectShow stuff */ + IGraphBuilder* pFilterGraph; + IMediaControl* media_control; + IMediaEvent* media_event; + IBasicAudio * basic_audio; + IMediaSeeking * media_seeking; + + /* Async event notification */ + HANDLE event_thread; + HANDLE stop_event; };
HRESULT init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; @@ -69,3 +88,18 @@ void call_sink(ConnectionPoint *This, DISPID dispid, DISPPARAMS *dispparams); void unregister_wmp_class(void) DECLSPEC_HIDDEN;
extern HINSTANCE wmp_instance DECLSPEC_HIDDEN; +static inline WCHAR *heap_strdupW(const WCHAR *str) +{ + WCHAR *ret; + + if(str) { + size_t size = strlenW(str)+1; + ret = heap_alloc(size*sizeof(WCHAR)); + if(ret) + memcpy(ret, str, size*sizeof(WCHAR)); + }else { + ret = NULL; + } + + return ret; +}