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 @@
-
+