From 01745e8374106c33b87b0efebd2c9aa1b172bc57 Mon Sep 17 00:00:00 2001 From: fgerlits Date: Fri, 4 Mar 2005 13:36:32 +0000 Subject: [PATCH] new, mostly working version of fade-in/fade-out --- .../modules/playlistExecutor/etc/playlist.xml | 12 +- .../PlaylistExecutor/AudioPlayerInterface.h | 12 +- .../playlistExecutor/src/AdviseSink.cxx | 9 +- .../playlistExecutor/src/HelixPlayer.cxx | 225 ++++++++++++------ .../playlistExecutor/src/HelixPlayer.h | 53 ++++- .../playlistExecutor/src/HelixPlayerTest.cxx | 4 +- .../playlistExecutor/var/playlist.smil | 2 +- 7 files changed, 223 insertions(+), 94 deletions(-) diff --git a/livesupport/modules/playlistExecutor/etc/playlist.xml b/livesupport/modules/playlistExecutor/etc/playlist.xml index 54d6ca9c3..b8b2e217d 100644 --- a/livesupport/modules/playlistExecutor/etc/playlist.xml +++ b/livesupport/modules/playlistExecutor/etc/playlist.xml @@ -38,21 +38,21 @@ + fadeOut="00:00:04" /> + relativeOffset="00:00:18.200000" > + fadeIn="00:00:06" + fadeOut="00:00:04" /> diff --git a/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h b/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h index 26aa470c4..a17c8e38f 100644 --- a/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h +++ b/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h @@ -22,7 +22,7 @@ Author : $Author: fgerlits $ - Version : $Revision: 1.5 $ + Version : $Revision: 1.6 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h,v $ ------------------------------------------------------------------------------*/ @@ -68,7 +68,7 @@ using namespace LiveSupport::Core; * A generic interface for playing audio files. * * @author $Author: fgerlits $ - * @version $Revision: 1.5 $ + * @version $Revision: 1.6 $ */ class AudioPlayerInterface { @@ -165,12 +165,18 @@ class AudioPlayerInterface virtual void stop(void) throw (std::logic_error) = 0; + /** * Play a playlist, with simulated fading. * * This is a stopgap method, and should be replaced as soon as * the SMIL animation issues are fixed in the Helix client. * + * The playlist is assumed to contain a URI field, which points + * to a SMIL file containing the same audio clips, with the same + * offsets, as the playlist. This can be ensured, for example, by + * calling Storage::WebStorageClient::acquirePlaylist(). + * * @param playlist the Playlist object to be played. * @exception std::invalid_argument playlist is invalid (e.g., * does not have a URI field, or there is no valid @@ -180,7 +186,7 @@ class AudioPlayerInterface * @exception std::runtime_error on errors thrown by the helix player */ virtual void - openAndStartPlaylist(Ptr::Ref playlist) + openAndStart(Ptr::Ref playlist) throw (std::invalid_argument, std::logic_error, std::runtime_error) diff --git a/livesupport/modules/playlistExecutor/src/AdviseSink.cxx b/livesupport/modules/playlistExecutor/src/AdviseSink.cxx index 257f08b64..17e6fb635 100644 --- a/livesupport/modules/playlistExecutor/src/AdviseSink.cxx +++ b/livesupport/modules/playlistExecutor/src/AdviseSink.cxx @@ -21,8 +21,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Author : $Author: maroy $ - Version : $Revision: 1.2 $ + Author : $Author: fgerlits $ + Version : $Revision: 1.3 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/Attic/AdviseSink.cxx,v $ ------------------------------------------------------------------------------*/ @@ -173,6 +173,11 @@ AdviseSink::OnPosLength(UINT32 ulPosition, UINT32 ulLength) throw () { helixPlayer->setPlaylength(ulLength); + try { + helixPlayer->implementFading(ulPosition); + } catch (std::runtime_error) { + // TODO: mark error; log it somewhere, maybe? + } return HXR_OK; } diff --git a/livesupport/modules/playlistExecutor/src/HelixPlayer.cxx b/livesupport/modules/playlistExecutor/src/HelixPlayer.cxx index 78e405192..31bfab832 100644 --- a/livesupport/modules/playlistExecutor/src/HelixPlayer.cxx +++ b/livesupport/modules/playlistExecutor/src/HelixPlayer.cxx @@ -22,7 +22,7 @@ Author : $Author: fgerlits $ - Version : $Revision: 1.14 $ + Version : $Revision: 1.15 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/Attic/HelixPlayer.cxx,v $ ------------------------------------------------------------------------------*/ @@ -85,14 +85,12 @@ static const std::string clntcoreName = "/clntcore.so"; /** * Magic number #1: max time to wait for an audio stream, in milliseconds */ -static const int getAudioStreamTimeOut = 10; +static const int getAudioStreamTimeOut = 5; /** - * Magic number #2: time to wait after getting crossfade interface, - * and before setting crossfade values, in milliseconds + * Magic number #2: schedule fading this many milliseconds in advance */ -static const int crossFadeWaitingTime = 50; - +static const int lookAheadTime = 2500; /* =============================================== local function prototypes */ @@ -398,10 +396,10 @@ DLLAccessPath* GetDLLAccessPath(void) /*------------------------------------------------------------------------------ - * Play a playlist, with simulated fading. + * Open a playlist, with simulated fading. *----------------------------------------------------------------------------*/ void -HelixPlayer :: openAndStartPlaylist(Ptr::Ref playlist) +HelixPlayer :: openAndStart(Ptr::Ref playlist) throw (std::invalid_argument, std::logic_error, std::runtime_error) @@ -409,96 +407,177 @@ HelixPlayer :: openAndStartPlaylist(Ptr::Ref playlist) if (!playlist || !playlist->getUri()) { throw std::invalid_argument("no playlist SMIL file found"); } + open(*playlist->getUri()); // may throw invalid_argument - bool hasFadeInfo = false; - int numberOfPlaylistElements = 0; - Playlist::const_iterator it = playlist->begin(); - while (it != playlist->end()) { - ++numberOfPlaylistElements; - if (it->second->getFadeInfo()) { - hasFadeInfo = true; - } - ++it; - } - start(); // may throw logic_error - if (!numberOfPlaylistElements || !hasFadeInfo) { - return; - } IHXAudioPlayer* audioPlayer = 0; - if (player->QueryInterface(IID_IHXAudioPlayer, (void**)&audioPlayer) - != HXR_OK + if (player->QueryInterface(IID_IHXAudioPlayer, + (void**)&audioPlayer) != HXR_OK || !audioPlayer) { throw std::runtime_error("can't get IHXAudioPlayer interface"); } - IHXAudioCrossFade* crossFade = 0; - if (audioPlayer->QueryInterface(IID_IHXAudioCrossFade, (void**)&crossFade) - != HXR_OK - || !crossFade) { - throw std::runtime_error("can't get IHXAudioCrossFade interface"); - } + int playlistSize = playlist->size(); + IHXAudioStream* audioStream[playlistSize]; + unsigned long playlength[playlistSize]; + unsigned long relativeOffset[playlistSize]; + unsigned long fadeIn[playlistSize]; + unsigned long fadeOut[playlistSize]; + Ptr::Ref sleepT(new time_duration(microseconds(10))); - IHXAudioStream* audioStream[numberOfPlaylistElements + 1]; - for (int i = 0; i < numberOfPlaylistElements; i++) { - int j = 0; - do { - TimeConversion::sleep(sleepT); - audioStream[i] = audioPlayer->GetAudioStream(i); - ++j; - if (j > getAudioStreamTimeOut * 100) { + bool hasFadeInfo = false; + Playlist::const_iterator it = playlist->begin(); + + for (int i = 0; i < playlistSize; ++i) { + audioStream[i] = audioPlayer->GetAudioStream(i); + int counter = 0; + while (!audioStream[i]) { + if (counter > getAudioStreamTimeOut * 100) { std::stringstream eMsg; eMsg << "can't get audio stream number " << i; throw std::runtime_error(eMsg.str()); } - } while (!audioStream[i]); - } - audioStream[numberOfPlaylistElements] = 0; // fade out last clip into 0 - - it = playlist->begin(); + TimeConversion::sleep(sleepT); - sleepT.reset(new time_duration(milliseconds(crossFadeWaitingTime))); - TimeConversion::sleep(sleepT); - - for (int i = 0; i < numberOfPlaylistElements; i++) { - - Ptr::Ref playlistElement = it->second; - if (!playlistElement->getFadeInfo()) { - ++it; - continue; + audioStream[i] = audioPlayer->GetAudioStream(i); + ++counter; } - // we assume i-th fade out is the same as (i+1)-st fade in - unsigned long crossFadeLength = playlistElement - ->getFadeInfo() - ->getFadeOut() - ->total_milliseconds(); - unsigned long fadeOutAt = playlistElement->getRelativeOffset() - ->total_milliseconds() - + playlistElement->getPlayable() - ->getPlaylength() - ->total_milliseconds() - - crossFadeLength; - - if (crossFadeLength) { -//std::cerr << "fadeOutAt: " << fadeOutAt << "\n" -// << "crossFadeLength: " << crossFadeLength << "\n"; - crossFade->CrossFade(audioStream[i], audioStream[i+1], - fadeOutAt, fadeOutAt, crossFadeLength); + relativeOffset[i] = it->second->getRelativeOffset() + ->total_milliseconds(); + playlength[i] = it->second->getPlayable()->getPlaylength() + ->total_milliseconds(); + + if (it->second->getFadeInfo()) { + hasFadeInfo = true; + fadeIn[i] = it->second->getFadeInfo() + ->getFadeIn()->total_milliseconds(); + fadeOut[i] = it->second->getFadeInfo() + ->getFadeOut()->total_milliseconds(); + } else { + fadeIn[i] = 0; + fadeOut[i] = 0; } - + ++it; } - for (int i = 0; i < numberOfPlaylistElements; i++) { + if (!hasFadeInfo) { + return; + } + + fadeIn[0] = 0; // can't do fade-in on the first audio clip, sorry + + fadeDataList.reset(new std::list); + FadeData fadeData; + + for (int i = 0; i < playlistSize; ++i) { + if (fadeIn[i]) { + fadeData.audioStreamFrom = 0; + fadeData.audioStreamTo = audioStream[i]; + fadeData.fadeAt = relativeOffset[i]; + fadeData.fadeLength = fadeIn[i]; + fadeDataList->push_back(fadeData); + } + + if (fadeOut[i]) { + if (i < playlistSize - 1 + && fadeOut[i] == fadeIn[i+1] + && relativeOffset[i] + playlength[i] + == relativeOffset[i+1] + fadeIn[i+1]) { + fadeData.audioStreamFrom = audioStream[i]; + fadeData.audioStreamTo = audioStream[i+1]; + fadeData.fadeAt = relativeOffset[i+1]; + fadeData.fadeLength = fadeIn[i+1]; + fadeDataList->push_back(fadeData); + fadeIn[i+1] = 0; + } else { + fadeData.audioStreamFrom = audioStream[i]; + fadeData.audioStreamTo = 0; + fadeData.fadeAt = relativeOffset[i] + + playlength[i] - fadeOut[i]; + fadeData.fadeLength = fadeOut[i]; + fadeDataList->push_back(fadeData); + } + } + HX_RELEASE(audioStream[i]); } - HX_RELEASE(crossFade); - HX_RELEASE(audioPlayer); + +//do { +// std::cerr << "\n"; +// std::list::const_iterator it = fadeDataList->begin(); +// while (it != fadeDataList->end()) { +// std::cerr << it->audioStreamFrom << " -> " +// << it->audioStreamTo << " : at " +// << it->fadeAt << ", for " +// << it->fadeLength << "\n"; +// ++it; +// } +// std::cerr << "\n"; +//} while (false); + +} + + +/*------------------------------------------------------------------------------ + * Activate the crossfading of clips in a playlist. + *----------------------------------------------------------------------------*/ +void +HelixPlayer :: implementFading(unsigned long position) + throw (std::runtime_error) +{ + if (!fadeDataList) { + return; + } + + std::list::iterator it = fadeDataList->begin(); + + while (it != fadeDataList->end()) { + unsigned long fadeAt = it->fadeAt; + + if (fadeAt < position) { // we missed it + it = fadeDataList->erase(it); + continue; + + } else if (fadeAt < position + lookAheadTime) { // we are on time + + IHXAudioPlayer* audioPlayer = 0; + if (player->QueryInterface(IID_IHXAudioPlayer, + (void**)&audioPlayer) != HXR_OK + || !audioPlayer) { + throw std::runtime_error("can't get IHXAudioPlayer interface"); + } + + IHXAudioCrossFade* crossFade = 0; + if (audioPlayer->QueryInterface(IID_IHXAudioCrossFade, + (void**)&crossFade) != HXR_OK + || !crossFade) { + throw std::runtime_error("can't get IHXAudioCrossFade " + "interface"); + } + +//std::cerr << "position:" << position << "\n" +// << "fadeAt: " << fadeAt << "\n" +// << "fadeLength: " << it->fadeLength << "\n\n"; + + crossFade->CrossFade(it->audioStreamFrom, it->audioStreamTo, + fadeAt, fadeAt, it->fadeLength); + + HX_RELEASE(crossFade); + HX_RELEASE(audioPlayer); + + it = fadeDataList->erase(it); + continue; + + } else { + ++it; + } + } } diff --git a/livesupport/modules/playlistExecutor/src/HelixPlayer.h b/livesupport/modules/playlistExecutor/src/HelixPlayer.h index cb7503423..2ae0b1d0c 100644 --- a/livesupport/modules/playlistExecutor/src/HelixPlayer.h +++ b/livesupport/modules/playlistExecutor/src/HelixPlayer.h @@ -22,7 +22,7 @@ Author : $Author: fgerlits $ - Version : $Revision: 1.12 $ + Version : $Revision: 1.13 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/Attic/HelixPlayer.h,v $ ------------------------------------------------------------------------------*/ @@ -40,6 +40,7 @@ #include "configure.h" #endif +#include #include #include "LiveSupport/Core/Configurable.h" @@ -54,6 +55,9 @@ #include "ClientContext.h" #include "LiveSupport/Core/Playlist.h" +#include + + namespace LiveSupport { namespace PlaylistExecutor { @@ -94,7 +98,7 @@ using namespace LiveSupport::Core; * * * @author $Author: fgerlits $ - * @version $Revision: 1.12 $ + * @version $Revision: 1.13 $ */ class HelixPlayer : virtual public Configurable, virtual public AudioPlayerInterface, @@ -135,7 +139,7 @@ class HelixPlayer : virtual public Configurable, * The Helix player. */ IHXPlayer * player; - + /** * The example client context. */ @@ -171,6 +175,44 @@ class HelixPlayer : virtual public Configurable, */ Ptr::Ref eventHandlerThread; + /** + * A type to contain the data about a single fade-in or fade-out + * event. + */ + struct FadeData { + IHXAudioStream* audioStreamFrom; + IHXAudioStream* audioStreamTo; + unsigned long fadeAt; + unsigned long fadeLength; + }; + + /** + * A list of fade-in/fade-out events. + * This is set by the openAndStartPlaylist() method, and the + * actual fading is done by implementFading(), called from + * AdviseSink::OnPosLength(). + */ + Ptr >::Ref fadeDataList; + + /** + * Declare AdviseSink::OnPosLength() to be a friend, so it can + * call the private method implementFading(). + */ + friend STDMETHODIMP + AdviseSink::OnPosLength(UINT32 ulPosition, + UINT32 ulLength) + throw (); + + /** + * Implement the actual fading scheduled by open(Ptr::Ref). + * This method is called from AdviceSink::OnPosLength(). + * DO NOT call this method directly. + * + * @param position the clip position + */ + void + implementFading(unsigned long position) + throw(std::runtime_error); public: /** @@ -336,9 +378,6 @@ class HelixPlayer : virtual public Configurable, * This is a stopgap method, and should be replaced as soon as * the SMIL animation issues are fixed in the Helix client. * - * Note: the method only reads the fade out value, and assumes - * that the following fade in value is equal to it. - * * The playlist is assumed to contain a URI field, which points * to a SMIL file containing the same audio clips, with the same * offsets, as the playlist. This can be ensured, for example, by @@ -353,7 +392,7 @@ class HelixPlayer : virtual public Configurable, * @exception std::runtime_error on errors thrown by the helix player */ virtual void - openAndStartPlaylist(Ptr::Ref playlist) + openAndStart(Ptr::Ref playlist) throw (std::invalid_argument, std::logic_error, std::runtime_error); diff --git a/livesupport/modules/playlistExecutor/src/HelixPlayerTest.cxx b/livesupport/modules/playlistExecutor/src/HelixPlayerTest.cxx index 25ab8065d..156e7bc04 100644 --- a/livesupport/modules/playlistExecutor/src/HelixPlayerTest.cxx +++ b/livesupport/modules/playlistExecutor/src/HelixPlayerTest.cxx @@ -22,7 +22,7 @@ Author : $Author: fgerlits $ - Version : $Revision: 1.9 $ + Version : $Revision: 1.10 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/Attic/HelixPlayerTest.cxx,v $ ------------------------------------------------------------------------------*/ @@ -419,7 +419,7 @@ HelixPlayerTest :: animationWorkaroundTest(void) playlist->setUri(uri); CPPUNIT_ASSERT_NO_THROW(helixPlayer->initialize()); - CPPUNIT_ASSERT_NO_THROW(helixPlayer->openAndStartPlaylist(playlist)); + CPPUNIT_ASSERT_NO_THROW(helixPlayer->openAndStart(playlist)); CPPUNIT_ASSERT(helixPlayer->isPlaying()); Ptr::Ref sleepT(new time_duration(microseconds(10))); diff --git a/livesupport/modules/playlistExecutor/var/playlist.smil b/livesupport/modules/playlistExecutor/var/playlist.smil index a44302802..1efdcba60 100644 --- a/livesupport/modules/playlistExecutor/var/playlist.smil +++ b/livesupport/modules/playlistExecutor/var/playlist.smil @@ -4,7 +4,7 @@