From 8b3e10ae6435c0bfc421a913f43049da5316a5c3 Mon Sep 17 00:00:00 2001 From: MichaÅ‚ CichoÅ„ Date: Sat, 5 Dec 2015 13:29:49 +0100 Subject: Refactor DirectShow player as backend. --- src/player/backends/direct_show.c | 463 ++++++++++++++++++++++++++++++++++++ src/player/player2.c | 476 +++++++++++--------------------------- src/player/player2.h | 45 ++-- src/player/player2_private.h | 34 +++ 4 files changed, 655 insertions(+), 363 deletions(-) create mode 100644 src/player/backends/direct_show.c create mode 100644 src/player/player2_private.h diff --git a/src/player/backends/direct_show.c b/src/player/backends/direct_show.c new file mode 100644 index 0000000..d6597c0 --- /dev/null +++ b/src/player/backends/direct_show.c @@ -0,0 +1,463 @@ +/* +Copyright (c) 2015 +Micha³ Cichoñ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* receive/play audio stream */ + +/* based on DShow example player */ + +#include "config.h" +#include "../player2_private.h" +#define COBJMACROS +#define INITGUID +#include +#include +#pragma comment(lib, "strmiids.lib") + +# define WM_GRAPH_EVENT (WM_APP + 1) + +enum { NO_GRAPH, RUNNING, PAUSED, STOPPED }; + +static struct _player_static_t +{ + bool done; + bool initialized; + bool hasCOM; +} BarPlayerGlobal = { 0 }; + +struct _player_t +{ + int state; + IGraphBuilder* graph; + IMediaControl* control; + IMediaEventEx* event; + IBasicAudio* audio; + IMediaSeeking* media; + float volume; // dB + float gain; // dB +}; + +static bool DSPlayerStaticInit(); +static void DSPlayerStaticTerm(void); + +static bool DSPlayerStaticInit() +{ + if (BarPlayerGlobal.done) + return BarPlayerGlobal.initialized; + + BarPlayerGlobal.done = true; + + atexit(DSPlayerStaticTerm); + + if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + return false; + + BarPlayerGlobal.hasCOM = true; + + BarPlayerGlobal.initialized = true; + + return true; +} + +static void DSPlayerStaticTerm(void) +{ + if (!BarPlayerGlobal.done) + return; + + if (BarPlayerGlobal.hasCOM) + { + CoUninitialize(); + BarPlayerGlobal.hasCOM = false; + } + + BarPlayerGlobal.initialized = false; + BarPlayerGlobal.done = false; +} + +static void DSPlayerApplyVolume(player2_t player) +{ + long v = (long)((player->volume + player->gain) * 100.0f); + + if (!player->audio) + return; + + if (v < -10000) + v = -10000; + if (v > 0) + v = 0; + + IBasicAudio_put_Volume(player->audio, v); +} + +static void DSPlayerTearDown(player2_t player) +{ + /* TODO: send final event */ + + if (player->graph) + { + IGraphBuilder_Release(player->graph); + player->graph = NULL; + } + + if (player->control) + { + IMediaControl_Release(player->control); + player->control = NULL; + } + + if (player->event) + { + IMediaEventEx_Release(player->event); + player->event = NULL; + } + + if (player->audio) + { + IBasicAudio_Release(player->audio); + player->audio = NULL; + } + + if (player->media) + { + IMediaSeeking_Release(player->media); + player->media = NULL; + } + + player->state = NO_GRAPH; +} + +static HRESULT DSPlayerBuild(player2_t player) +{ + HRESULT hr; + + DSPlayerTearDown(player); + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, &player->graph); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaControl, &player->control); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaEventEx, &player->event); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IBasicAudio, &player->audio); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaSeeking, &player->media); + if (FAILED(hr)) + return hr; + + hr = IMediaEventEx_SetNotifyWindow(player->event, (OAHWND)NULL, WM_GRAPH_EVENT, (LONG_PTR)player); + if (FAILED(hr)) + return hr; + + player->state = STOPPED; + + return S_OK; +} + +static HRESULT DSPlayerAddFilterByCLSID(IGraphBuilder *pGraph, REFGUID clsid, IBaseFilter **ppF, LPCWSTR wszName) +{ + IBaseFilter *pFilter = NULL; + HRESULT hr; + *ppF = 0; + + hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, &pFilter); + if (FAILED(hr)) + goto done; + + hr = IGraphBuilder_AddFilter(pGraph, pFilter, wszName); + if (FAILED(hr)) + goto done; + + *ppF = pFilter; + + IBaseFilter_AddRef(*ppF); + +done: + if (pFilter) + IBaseFilter_Release(pFilter); + + return hr; +} + +static HRESULT DSPlayerRender(player2_t player, IBaseFilter* source) +{ + BOOL bRenderedAnyPin = FALSE; + + IPin* pin = NULL; + IEnumPins *enumPins = NULL; + IBaseFilter *audioRenderer = NULL; + IFilterGraph2* filter = NULL; + + HRESULT hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IFilterGraph2, &filter); + if (FAILED(hr)) + return hr; + + hr = DSPlayerAddFilterByCLSID(player->graph, &CLSID_DSoundRender, &audioRenderer, L"Audio Renderer"); + if (FAILED(hr)) + goto done; + + hr = IBaseFilter_EnumPins(source, &enumPins); + if (FAILED(hr)) + goto done; + + while (S_OK == IEnumPins_Next(enumPins, 1, &pin, NULL)) + { + HRESULT hr2 = IFilterGraph2_RenderEx(filter, pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL); + + IPin_Release(pin); + if (SUCCEEDED(hr2)) + bRenderedAnyPin = TRUE; + } + +done: + if (enumPins) + IEnumPins_Release(enumPins); + if (enumPins) + IBaseFilter_Release(audioRenderer); + if (enumPins) + IFilterGraph2_Release(filter); + + if (SUCCEEDED(hr) && !bRenderedAnyPin) + hr = VFW_E_CANNOT_RENDER; + + return hr; +} + +static player2_t DSPlayerCreate() +{ + player2_t out = NULL; + + if (!DSPlayerStaticInit()) + return NULL; + + out = malloc(sizeof(struct _player_t)); + if (!out) + return NULL; + + memset(out, 0, sizeof(struct _player_t)); + + return out; +} + +static void DSPlayerDestroy(player2_t player) +{ + DSPlayerTearDown(player); + free(player); +} + +static void DSPlayerSetVolume(player2_t player, float volume) +{ + player->volume = volume; + DSPlayerApplyVolume(player); +} + +static float DSPlayerGetVolume(player2_t player) +{ + return player->volume; +} + +static void DSPlayerSetGain(player2_t player, float gain) +{ + player->gain = gain; + DSPlayerApplyVolume(player); +} + +static float DSPlayerGetGain(player2_t player) +{ + return player->gain; +} + +static double DSPlayerGetDuration(player2_t player) +{ + LONGLONG time; + if (SUCCEEDED(IMediaSeeking_GetDuration(player->media, &time))) + return time / 10000000.0; + else + return 0; +} + +static double DSPlayerGetTime(player2_t player) +{ + LONGLONG time; + if (SUCCEEDED(IMediaSeeking_GetCurrentPosition(player->media, &time))) + return time / 10000000.0; + else + return 0; +} + +static bool DSPlayerOpen(player2_t player, const char* url) +{ + IBaseFilter* source = NULL; + HRESULT hr; + wchar_t* wideUrl = NULL; + size_t urlSize; + int result; + + hr = DSPlayerBuild(player); + if (FAILED(hr)) + goto done; + + urlSize = strlen(url); + result = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, url, urlSize, NULL, 0); + wideUrl = malloc((result + 1) * sizeof(wchar_t)); + if (!wideUrl) + { + hr = E_OUTOFMEMORY; + goto done; + } + memset(wideUrl, 0, (result + 1) * sizeof(wchar_t)); + + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, url, urlSize, wideUrl, result); + + hr = IGraphBuilder_AddSourceFilter(player->graph, wideUrl, NULL, &source); + if (FAILED(hr)) + goto done; + + hr = DSPlayerRender(player, source); + + DSPlayerApplyVolume(player); + +done: + if (wideUrl) + free(wideUrl); + if (FAILED(hr)) + DSPlayerTearDown(player); + if (source) + IBaseFilter_Release(source); + + return SUCCEEDED(hr); +} + +static bool DSPlayerPlay(player2_t player) +{ + HRESULT hr; + + if (player->state != PAUSED && player->state != STOPPED) + return false; /* wrong state */ + + hr = IMediaControl_Run(player->control); + if (SUCCEEDED(hr)) + player->state = RUNNING; + + return SUCCEEDED(hr); +} + +static bool DSPlayerPause(player2_t player) +{ + HRESULT hr; + + if (player->state != RUNNING) + return false; /* wrong state */ + + hr = IMediaControl_Pause(player->control); + if (SUCCEEDED(hr)) + player->state = PAUSED; + + return SUCCEEDED(hr); +} + +static bool DSPlayerStop(player2_t player) +{ + HRESULT hr; + + if (player->state != RUNNING && player->state != PAUSED) + return false; /* wrong state */ + + hr = IMediaControl_Stop(player->control); + if (SUCCEEDED(hr)) + player->state = STOPPED; + + return SUCCEEDED(hr); +} + +static bool DSPlayerFinish(player2_t player) +{ + if (!player->control) + return false; + + DSPlayerTearDown(player); + return true; +} + +static bool DSPlayerIsPlaying(player2_t player) +{ + return player->state == RUNNING; +} + +static bool DSPlayerIsPaused(player2_t player) +{ + return player->state == PAUSED; +} + +static bool DSPlayerIsStopped(player2_t player) +{ + return player->state == STOPPED; +} + +static bool DSPlayerIsFinished(player2_t player) +{ + LONGLONG time; + LONGLONG duration; + + if (!player->media || player->state == NO_GRAPH) + return true; + + if (player->state != RUNNING && player->state != STOPPED) + return false; + + if (FAILED(IMediaSeeking_GetDuration(player->media, &duration)) || + FAILED(IMediaSeeking_GetCurrentPosition(player->media, &time))) + return true; + + return time >= duration; +} + +player2_iface player2_direct_show = +{ + .Name = "Direct Show", + .Create = DSPlayerCreate, + .Destroy = DSPlayerDestroy, + .SetVolume = DSPlayerSetVolume, + .GetVolume = DSPlayerGetVolume, + .SetGain = DSPlayerSetGain, + .GetGain = DSPlayerGetGain, + .GetDuration = DSPlayerGetDuration, + .GetTime = DSPlayerGetTime, + .Open = DSPlayerOpen, + .Play = DSPlayerPlay, + .Pause = DSPlayerPause, + .Stop = DSPlayerStop, + .Finish = DSPlayerFinish, + .IsPlaying = DSPlayerIsPlaying, + .IsPaused = DSPlayerIsPaused, + .IsStopped = DSPlayerIsStopped, + .IsFinished = DSPlayerIsFinished +}; diff --git a/src/player/player2.c b/src/player/player2.c index 01fe33c..ed082d3 100644 --- a/src/player/player2.c +++ b/src/player/player2.c @@ -1,6 +1,6 @@ /* Copyright (c) 2015 - Micha³ Cichoñ + Micha³ Cichoñ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,384 +26,178 @@ THE SOFTWARE. /* based on DShow example player */ #include "config.h" -#include "player2.h" -#define COBJMACROS -#define INITGUID -#include -#include -#pragma comment(lib, "strmiids.lib") - -# define WM_GRAPH_EVENT (WM_APP + 1) - -enum { NO_GRAPH, RUNNING, PAUSED, STOPPED }; - -static struct _player_static_t { - bool done; - bool initialized; - bool hasCOM; -} BarPlayerGlobal = { 0 }; - -struct _player_t { - int state; - IGraphBuilder* graph; - IMediaControl* control; - IMediaEventEx* event; - IBasicAudio* audio; - IMediaSeeking* media; - float volume; // dB - float gain; // dB -}; - -static bool BarPlayer2StaticInit(); -static void BarPlayer2StaticTerm(void); - -static bool BarPlayer2StaticInit () { - if (BarPlayerGlobal.done) - return BarPlayerGlobal.initialized; - - BarPlayerGlobal.done = true; - - atexit(BarPlayer2StaticTerm); - - if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) - return false; - - BarPlayerGlobal.hasCOM = true; - - BarPlayerGlobal.initialized = true; - - return true; -} - -static void BarPlayer2StaticTerm(void) { - if (!BarPlayerGlobal.done) - return; - - if (BarPlayerGlobal.hasCOM) { - CoUninitialize(); - BarPlayerGlobal.hasCOM = false; - } - - BarPlayerGlobal.initialized = false; - BarPlayerGlobal.done = false; -} - -static void BarPlayer2ApplyVolume(player2_t player) { - long v = (long)((player->volume + player->gain) * 100.0f); - - if (!player->audio) - return; - - if (v < -10000) - v = -10000; - if (v > 0) - v = 0; - - IBasicAudio_put_Volume(player->audio, v); -} - -static void BarPlayer2TearDown(player2_t player) { - /* TODO: send final event */ - - if (player->graph) { - IGraphBuilder_Release(player->graph); - player->graph = NULL; - } - - if (player->control) { - IMediaControl_Release(player->control); - player->control = NULL; - } - - if (player->event) { - IMediaEventEx_Release(player->event); - player->event = NULL; - } - - if (player->audio) { - IBasicAudio_Release(player->audio); - player->audio = NULL; - } - - if (player->media) { - IMediaSeeking_Release(player->media); - player->media = NULL; - } - - player->state = NO_GRAPH; -} - -static HRESULT BarPlayer2Build(player2_t player) { - HRESULT hr; - - BarPlayer2TearDown(player); - - hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, &player->graph); - if (FAILED(hr)) - return hr; - - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaControl, &player->control); - if (FAILED(hr)) - return hr; +#include "player2_private.h" +#include +#include - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaEventEx, &player->event); - if (FAILED(hr)) - return hr; +# define length_of(x) (sizeof(x)/sizeof(*(x))) - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IBasicAudio, &player->audio); - if (FAILED(hr)) - return hr; - - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaSeeking, &player->media); - if (FAILED(hr)) - return hr; +static player2_iface* player2_backends[] = +{ + &player2_direct_show +}; - hr = IMediaEventEx_SetNotifyWindow(player->event, (OAHWND)NULL, WM_GRAPH_EVENT, (LONG_PTR)player); - if (FAILED(hr)) - return hr; +struct _player_t +{ + player2_iface* backend; + player2_t player; +}; - player->state = STOPPED; +bool BarPlayer2Init(player2_t* outPlayer) +{ + player2_t player; + struct _player_t result; + int i; - return S_OK; -} + memset(&result, 0, sizeof(struct _player_t)); -static HRESULT BarPlayer2AddFilterByCLSID(IGraphBuilder *pGraph, REFGUID clsid, IBaseFilter **ppF, LPCWSTR wszName) { - IBaseFilter *pFilter = NULL; - HRESULT hr; - *ppF = 0; + for (i = 0; i < length_of(player2_backends); ++i) + { + player2_iface* backend = player2_backends[i]; - hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, &pFilter); - if (FAILED(hr)) - goto done; + result.player = backend->Create(); + if (result.player) + { + result.backend = backend; + break; + } + } - hr = IGraphBuilder_AddFilter(pGraph, pFilter, wszName); - if (FAILED(hr)) - goto done; + if (!result.backend) + return false; - *ppF = pFilter; + player = malloc(sizeof(struct _player_t)); + if (!player) + return false; - IBaseFilter_AddRef(*ppF); + *player = result; -done: - if (pFilter) - IBaseFilter_Release(pFilter); + *outPlayer = player; - return hr; + return true; } -static HRESULT BarPlayer2Render(player2_t player, IBaseFilter* source) { - BOOL bRenderedAnyPin = FALSE; - - IPin* pin = NULL; - IEnumPins *enumPins = NULL; - IBaseFilter *audioRenderer = NULL; - IFilterGraph2* filter = NULL; - - HRESULT hr; - - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IFilterGraph2, &filter); - if (FAILED(hr)) - return hr; - - hr = BarPlayer2AddFilterByCLSID(player->graph, &CLSID_DSoundRender, &audioRenderer, L"Audio Renderer"); - if (FAILED(hr)) - goto done; - - hr = IBaseFilter_EnumPins(source, &enumPins); - if (FAILED(hr)) - goto done; - - while (S_OK == IEnumPins_Next(enumPins, 1, &pin, NULL)) - { - HRESULT hr2 = IFilterGraph2_RenderEx(filter, pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL); - - IPin_Release(pin); - if (SUCCEEDED(hr2)) - bRenderedAnyPin = TRUE; - } - -done: - if (enumPins) - IEnumPins_Release(enumPins); - if (enumPins) - IBaseFilter_Release(audioRenderer); - if (enumPins) - IFilterGraph2_Release(filter); - - if (SUCCEEDED(hr) && !bRenderedAnyPin) - hr = VFW_E_CANNOT_RENDER; - - return hr; +void BarPlayer2Destroy(player2_t player) +{ + if (player->player) + { + player->backend->Destroy(player->player); + player->player = NULL; + } } -bool BarPlayer2Init(player2_t* player) { - - if (!BarPlayer2StaticInit ()) - return false; - - player2_t out = malloc(sizeof(struct _player_t)); - if (!out) - return false; - - memset(out, 0, sizeof(struct _player_t)); - - *player = out; - - return true; +void BarPlayer2SetVolume(player2_t player, float volume) +{ + if (player->player) + player->backend->SetVolume(player->player, volume); } -void BarPlayer2Destroy(player2_t player) { - BarPlayer2TearDown(player); - free(player); +float BarPlayer2GetVolume(player2_t player) +{ + if (player->player) + return player->backend->GetVolume(player->player); + else + return 0.0f; } -void BarPlayer2SetVolume(player2_t player, float volume) { - player->volume = volume; - BarPlayer2ApplyVolume(player); +void BarPlayer2SetGain(player2_t player, float gainDb) +{ + if (player->player) + player->backend->SetGain(player->player, gainDb); } -float BarPlayer2GetVolume(player2_t player) { - return player->volume; +float BarPlayer2GetGain(player2_t player) +{ + if (player->player) + return player->backend->GetGain(player->player); + else + return 0.0f; } -void BarPlayer2SetGain(player2_t player, float gain) { - player->gain = gain; - BarPlayer2ApplyVolume(player); +double BarPlayer2GetDuration(player2_t player) +{ + if (player->player) + return player->backend->GetDuration(player->player); + else + return 0.0f; } -float BarPlayer2GetGain(player2_t player) { - return player->gain; +double BarPlayer2GetTime(player2_t player) +{ + if (player->player) + return player->backend->GetTime(player->player); + else + return 0.0f; } -double BarPlayer2GetDuration(player2_t player) { - LONGLONG time; - if (SUCCEEDED(IMediaSeeking_GetDuration(player->media, &time))) - return time / 10000000.0; - else - return 0; +bool BarPlayer2Open(player2_t player, const char* url) +{ + if (player->player) + return player->backend->Open(player->player, url); + else + return false; } -double BarPlayer2GetTime(player2_t player) { - LONGLONG time; - if (SUCCEEDED(IMediaSeeking_GetCurrentPosition(player->media, &time))) - return time / 10000000.0; - else - return 0; +bool BarPlayer2Play(player2_t player) +{ + if (player->player) + return player->backend->Play(player->player); + else + return false; } -bool BarPlayer2Open(player2_t player, const char* url) { - IBaseFilter* source = NULL; - HRESULT hr; - wchar_t* wideUrl = NULL; - size_t urlSize; - int result; - - hr = BarPlayer2Build(player); - if (FAILED(hr)) - goto done; - - urlSize = strlen(url); - result = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, url, urlSize, NULL, 0); - wideUrl = malloc((result + 1) * sizeof(wchar_t)); - if (!wideUrl) { - hr = E_OUTOFMEMORY; - goto done; - } - memset(wideUrl, 0, (result + 1) * sizeof(wchar_t)); - - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, url, urlSize, wideUrl, result); - - hr = IGraphBuilder_AddSourceFilter(player->graph, wideUrl, NULL, &source); - if (FAILED(hr)) - goto done; - - hr = BarPlayer2Render(player, source); - - BarPlayer2ApplyVolume(player); - -done: - if (wideUrl) - free(wideUrl); - if (FAILED(hr)) - BarPlayer2TearDown(player); - if (source) - IBaseFilter_Release(source); - - return SUCCEEDED(hr); +bool BarPlayer2Pause(player2_t player) +{ + if (player->player) + return player->backend->Pause(player->player); + else + return false; } -bool BarPlayer2Play(player2_t player) { - HRESULT hr; - - if (player->state != PAUSED && player->state != STOPPED) - return false; /* wrong state */ - - hr = IMediaControl_Run(player->control); - if (SUCCEEDED(hr)) - player->state = RUNNING; - - return SUCCEEDED(hr); +bool BarPlayer2Stop(player2_t player) +{ + if (player->player) + return player->backend->Stop(player->player); + else + return false; } -bool BarPlayer2Pause(player2_t player) { - HRESULT hr; - - if (player->state != RUNNING) - return false; /* wrong state */ - - hr = IMediaControl_Pause(player->control); - if (SUCCEEDED(hr)) - player->state = PAUSED; - - return SUCCEEDED(hr); +bool BarPlayer2Finish(player2_t player) +{ + if (player->player) + return player->backend->Finish(player->player); + else + return false; } -bool BarPlayer2Stop(player2_t player) { - HRESULT hr; - - if (player->state != RUNNING && player->state != PAUSED) - return false; /* wrong state */ - - hr = IMediaControl_Stop(player->control); - if (SUCCEEDED(hr)) - player->state = STOPPED; - - return SUCCEEDED(hr); -} - -bool BarPlayer2Finish(player2_t player) { - if (!player->control) - return false; - - BarPlayer2TearDown(player); - return true; -} - -bool BarPlayer2IsPlaying(player2_t player) { - return player->state == RUNNING; +bool BarPlayer2IsPlaying(player2_t player) +{ + if (player->player) + return player->backend->IsPlaying(player->player); + else + return false; } - -bool BarPlayer2IsPaused(player2_t player) { - return player->state == PAUSED; + +bool BarPlayer2IsPaused(player2_t player) +{ + if (player->player) + return player->backend->IsPaused(player->player); + else + return false; } -bool BarPlayer2IsStopped(player2_t player) { - return player->state == STOPPED; -} - -bool BarPlayer2IsFinished(player2_t player) { - LONGLONG time; - LONGLONG duration; - - if (!player->media || player->state == NO_GRAPH) - return true; - - if (player->state != RUNNING && player->state != STOPPED) - return false; - - if (FAILED(IMediaSeeking_GetDuration(player->media, &duration)) || - FAILED(IMediaSeeking_GetCurrentPosition(player->media, &time))) - return true; - - return time >= duration; -} +bool BarPlayer2IsStopped(player2_t player) +{ + if (player->player) + return player->backend->IsStopped(player->player); + else + return false; +} + +bool BarPlayer2IsFinished(player2_t player) +{ + if (player->player) + return player->backend->IsFinished(player->player); + else + return true; +} \ No newline at end of file diff --git a/src/player/player2.h b/src/player/player2.h index b426ee2..d50d76f 100644 --- a/src/player/player2.h +++ b/src/player/player2.h @@ -1,6 +1,6 @@ /* Copyright (c) 2015 - Micha³ Cichoñ + Micha³ Cichoñ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef SRC_PLAYER2_H_CN979RE9 -#define SRC_PLAYER2_H_CN979RE9 +#ifndef __PIANOBAR_PLAYER2_H__ +#define __PIANOBAR_PLAYER2_H__ +#pragma once #include "config.h" @@ -30,23 +31,23 @@ THE SOFTWARE. typedef struct _player_t *player2_t; -bool BarPlayer2Init (player2_t*); -void BarPlayer2Destroy (player2_t); -void BarPlayer2SetVolume (player2_t,float); -float BarPlayer2GetVolume (player2_t); -void BarPlayer2SetGain (player2_t, float); -float BarPlayer2GetGain (player2_t); -double BarPlayer2GetDuration (player2_t); -double BarPlayer2GetTime (player2_t); -bool BarPlayer2Open (player2_t, const char*); -bool BarPlayer2Play (player2_t); -bool BarPlayer2Pause (player2_t); -bool BarPlayer2Stop (player2_t); -bool BarPlayer2Finish (player2_t); -bool BarPlayer2IsPlaying (player2_t); -bool BarPlayer2IsPaused (player2_t); -bool BarPlayer2IsStopped (player2_t); -bool BarPlayer2IsFinished (player2_t); - -#endif /* SRC_PLAYER2_H_CN979RE9 */ +bool BarPlayer2Init(player2_t* outPlayer); +void BarPlayer2Destroy(player2_t player); +void BarPlayer2SetVolume(player2_t player, float volume); +float BarPlayer2GetVolume(player2_t player); +void BarPlayer2SetGain(player2_t player, float gainDb); +float BarPlayer2GetGain(player2_t player); +double BarPlayer2GetDuration(player2_t player); +double BarPlayer2GetTime(player2_t player); +bool BarPlayer2Open(player2_t player, const char* url); +bool BarPlayer2Play(player2_t player); +bool BarPlayer2Pause(player2_t player); +bool BarPlayer2Stop(player2_t player); +bool BarPlayer2Finish(player2_t player); +bool BarPlayer2IsPlaying(player2_t player); +bool BarPlayer2IsPaused(player2_t player); +bool BarPlayer2IsStopped(player2_t player); +bool BarPlayer2IsFinished(player2_t player); + +#endif /* __PIANOBAR_PLAYER2_H__ */ diff --git a/src/player/player2_private.h b/src/player/player2_private.h new file mode 100644 index 0000000..054b81f --- /dev/null +++ b/src/player/player2_private.h @@ -0,0 +1,34 @@ +#ifndef __PIANOBAR_PLAYER2_PRIVATE_H__ +#define __PIANOBAR_PLAYER2_PRIVATE_H__ +#pragma once + +#include "config.h" +#include +#include "player2.h" + +typedef struct _player2_iface +{ + const char* Name; + player2_t (*Create) (); + void (*Destroy) (player2_t player); + void (*SetVolume) (player2_t player, float volume); + float (*GetVolume) (player2_t player); + void (*SetGain) (player2_t player, float gainDb); + float (*GetGain) (player2_t player); + double (*GetDuration) (player2_t player); + double (*GetTime) (player2_t player); + bool (*Open) (player2_t player, const char* url); + bool (*Play) (player2_t player); + bool (*Pause) (player2_t player); + bool (*Stop) (player2_t player); + bool (*Finish) (player2_t player); + bool (*IsPlaying) (player2_t player); + bool (*IsPaused) (player2_t player); + bool (*IsStopped) (player2_t player); + bool (*IsFinished) (player2_t player); +} player2_iface; + +extern player2_iface player2_direct_show; +extern player2_iface player2_windows_media_foundation; + +#endif /* __PIANOBAR_PLAYER2_PRIVATE_H__ */ -- cgit v1.2.3