+
+#include "LiveSupport/Core/Configurable.h"
+#include "LiveSupport/PlaylistExecutor/AudioPlayerInterface.h"
+
+#include "LiveSupport/Core/Playlist.h"
+
+
+namespace LiveSupport {
+namespace PlaylistExecutor {
+
+using namespace boost::posix_time;
+
+using namespace LiveSupport;
+using namespace LiveSupport::Core;
+
+/* ================================================================ constants */
+
+
+/* =================================================================== macros */
+
+
+/* =============================================================== data types */
+
+/**
+ * A class to play audio files and some SMIL files through the Gstreamer
+ * library.
+ * This class can be configured with the following XML element.
+ *
+ *
+ *
+ *
+ *
+ * where the dllPath is the path to the directory containing the Helix
+ * library shared objects. The optional audioDevice argument sets the
+ * AUDIO environment variable which is read by the Helix client.
+ *
+ * There are two parameters which are only there because the current version
+ * of the Helix client does not handle animation tags in SMIL files properly.
+ * They will be removed from later versions.
+ *
+ * - audioStreamTimeOut (milliseconds) - the time to wait for each
+ * GetAudioStream() operation before a timeout occurs;
+ * the default is 5;
+ * - fadeLookAheadTime (milliseconds) - each fade-in or fade-out is
+ * scheduled (using IHXAudioCrossFade::CrossFade()) this
+ * much time before it is to happen; the default is 2500.
+ *
+ *
+ * The DTD for the above configuration is the following:
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @author $Author: maroy $
+ * @version $Revision: 1.1 $
+ */
+class GstreamerPlayer : virtual public Configurable,
+ virtual public AudioPlayerInterface
+{
+ private:
+ /**
+ * The name of the configuration XML elmenent used by GstreamerPlayer
+ */
+ static const std::string configElementNameStr;
+
+ /**
+ * The pipeline inside the player
+ */
+ GstElement * pipeline;
+
+ /**
+ * The file source element.
+ */
+ GstElement * filesrc;
+
+ /**
+ * The typefinder element.
+ */
+ GstElement * typefinder;
+
+ /**
+ * The decoder element.
+ */
+ GstElement * decoder;
+
+ /**
+ * The source pad of the decoder element.
+ * This pad can be used to navigate in a time-based manner.
+ */
+ GstPad * decoderSrc;
+
+ /**
+ * The audio sink
+ */
+ GstElement * audiosink;
+
+ /**
+ * The list of factories considered when creating the pipeline.
+ */
+ static GList * factories;
+
+ /**
+ * The URL to play.
+ */
+ std::string url;
+
+ /**
+ * Flag to indicate if this object has been initialized.
+ */
+ bool initialized;
+
+ /**
+ * The audio device to play on.
+ */
+ std::string audioDevice;
+
+ /**
+ * The type for the vector of listeners.
+ * Just a shorthand notation, to make reference to the type
+ * easier.
+ */
+ typedef std::vector
+ ListenerVector;
+
+ /**
+ * A vector of event listeners, which are interested in events
+ * related to this player.
+ */
+ ListenerVector listeners;
+
+ /**
+ * Initialize the list of factories that we're interested in
+ * when creating the pipeline.
+ */
+ static void
+ initFactories(void) throw ();
+
+ /**
+ * Filter plugins so that only factories for demuxers, decoders
+ * and parsers are considered.
+ *
+ * @param feature the features of the plugin to check
+ * @param data not used
+ * @return true of the supplied feature is a factory for a demuxer,
+ * decoder or parser, false otherwise
+ */
+ static gboolean
+ featureFilter(GstPluginFeature * feature,
+ gpointer data)
+ throw ();
+
+ /**
+ * Compare the plugin features according to their rank.
+ *
+ * @param feature1 one of the features to compare
+ * @param feature2 the second feature to compare
+ * @return 0 of the ranks are equal, <0 if feature1 is ranked lower,
+ * >0 if feature1 is ranked higher
+ */
+ static gint
+ compareRanks(GstPluginFeature * feature1,
+ GstPluginFeature * feature2)
+ throw ();
+
+ /**
+ * Handler to recieve errors from gstreamer.
+ *
+ * @param pipeline the pipeline generating the error
+ * @param source the source of the error
+ * @param error the error itself
+ * @param debug debug info
+ * @param self pointer to the associated GsreamerPlayer object.
+ */
+ static void
+ errorHandler(GstElement * pipeline,
+ GstElement * source,
+ GError * error,
+ gchar * debug,
+ gpointer self) throw ();
+
+ /**
+ * Even handler for when a matching type was found by typefineder.
+ *
+ * @param typefinder the typefineder that found the match
+ * @param probability the probability of the match
+ * @param caps the capabilities of the found match
+ * @param self pointer to the associated GstreamPlayer object.
+ */
+ static void
+ typeFound(GstElement * typefinder,
+ guint probability,
+ GstCaps * caps,
+ gpointer self) throw ();
+
+ /**
+ * Event handler for when a new dynamic pad is found. Plug the found
+ * pad by calling tryToPlug().
+ *
+ * @param element the element where the new pad came up.
+ * @param pad the new pad
+ * @param self reference to the associated GstreamerPlayer object
+ */
+ static void
+ newPad(GstElement * element,
+ GstPad * pad,
+ gpointer self)
+ throw ();
+
+ /**
+ * Event handler for the state change event on the pipeline.
+ * Use this to catch events like playing has ended.
+ *
+ * @param element the pipeline the event change has occured at
+ * @param oldState the old state
+ * @param newState the new state
+ * @param self a pointer to the associated GstreamerPlayer object.
+ */
+ static void
+ stateChange(GstElement * element,
+ gint oldState,
+ gint newState,
+ gpointer self)
+ throw ();
+
+ /**
+ * Try to plug a matching element to the specified pad
+ *
+ * @param pad the pad to plug to
+ * @param caps find a matching element to these capabilities
+ * @exception std::logic_error if couldn't plug
+ */
+ void
+ tryToPlug(GstPad * pad,
+ const GstCaps * caps)
+ throw (std::logic_error);
+
+ /**
+ * Close the link between a source pad and a sink element
+ *
+ * @param srcpad the source pad to link up
+ * @param sinkelement link srcpad to this element
+ * @param padname use this pad from sinkelement to link to
+ * @param templlist use pads from these templates
+ */
+ void
+ closeLink(GstPad * srcpad,
+ GstElement * sinkelement,
+ const gchar * padname,
+ const GList * templlist)
+ throw ();
+
+ /**
+ * Send the onStop event to all attached listeners.
+ */
+ virtual void
+ fireOnStopEvent(void) throw ();
+
+ /**
+ * Tell if the object is currently opened (has a file source to
+ * read.)
+ *
+ * @return true if the object is currently opened, false otherwise.
+ */
+ bool
+ isOpened(void) throw ();
+
+
+ public:
+ /**
+ * Constructor.
+ */
+ GstreamerPlayer(void) throw ()
+ {
+ pipeline = 0;
+ filesrc = 0;
+ typefinder = 0;
+ decoder = 0;
+ decoderSrc = 0;
+ audiosink = 0;
+ initialized = false;
+ }
+
+ /**
+ * A virtual destructor, as this class has virtual functions.
+ */
+ virtual
+ ~GstreamerPlayer(void) throw ()
+ {
+ deInitialize();
+ }
+
+ /**
+ * Return the name of the XML element this object expects
+ * to be sent to a call to configure().
+ *
+ * @return the name of the expected XML configuration element.
+ */
+ static const std::string
+ getConfigElementName(void) throw ()
+ {
+ return configElementNameStr;
+ }
+
+ /**
+ * Configure the object based on the XML element supplied.
+ *
+ * @param element the XML element to configure the object from.
+ * @exception std::invalid_argument if the supplied XML element
+ * contains bad configuraiton information
+ * @exception std::logic_error if the scheduler daemon has already
+ * been configured, and can not be reconfigured.
+ */
+ virtual void
+ configure(const xmlpp::Element & element)
+ throw (std::invalid_argument,
+ std::logic_error);
+
+ /**
+ * Initialize the Helix Player object, so that it is ready to
+ * play audio files.
+ *
+ * @exception std::exception on initialization problems.
+ */
+ virtual void
+ initialize(void) throw (std::exception);
+
+ /**
+ * De-initialize the Helix Player object.
+ */
+ virtual void
+ deInitialize(void) throw ();
+
+ /**
+ * Attach an event listener for this audio player.
+ * After this call, the supplied event will recieve all events
+ * related to this audio player.
+ *
+ * @param eventListener the event listener to register.
+ * @see #detach
+ */
+ virtual void
+ attachListener(AudioPlayerEventListener* eventListener)
+ throw ();
+
+ /**
+ * Detach an event listener for this audio player.
+ *
+ * @param eventListener the event listener to unregister.
+ * @exception std::invalid_argument if the supplied event listener
+ * has not been previously registered.
+ * @see #attach
+ */
+ virtual void
+ detachListener(AudioPlayerEventListener* eventListener)
+ throw (std::invalid_argument);
+
+ /**
+ * Set the audio device used for playback.
+ *
+ * @param deviceName the new device name, e.g., /dev/dsp or
+ * plughw:0,0
+ * @return true if successful, false if not
+ */
+ virtual bool
+ setAudioDevice(const std::string &deviceName)
+ throw ();
+
+ /**
+ * Specify which audio resource to play.
+ * The file may be a playlist, referencing other files, which
+ * will be accessed automatically.
+ * Note: this call will not start playing! You will
+ * have to call the start() function to begin playing.
+ * Always close any opened resource with a call to close().
+ *
+ * @param fileUrl a URL to a file
+ * @exception std::invalid_argument if the supplied fileUrl
+ * seems to be invalid.
+ * @see #close
+ * @see #start
+ */
+ virtual void
+ open(const std::string fileUrl) throw (std::invalid_argument);
+
+ /**
+ * Close an audio source that was opened.
+ *
+ * @see #open
+ */
+ virtual void
+ close(void) throw ();
+
+ /**
+ * Start playing.
+ * This call will start playing the active playlist, which was
+ * set by a previous call to open().
+ * Playing can be stopped by calling stop().
+ *
+ * @exception std::logic_error if there was no previous call to
+ * open().
+ * @see #open
+ * @see #stop
+ */
+ virtual void
+ start(void) throw (std::logic_error);
+
+ /**
+ * Pause the player.
+ * Playing can be resumed by calling start().
+ *
+ * @exception std::logic_error if there was no previous call to
+ * open().
+ * @see #open
+ * @see #start
+ */
+ virtual void
+ pause(void) throw (std::logic_error);
+
+ /**
+ * Tell if we're currently playing.
+ *
+ * @return true of the player is currently playing, false
+ * otherwise.
+ */
+ virtual bool
+ isPlaying(void) throw ();
+
+ /**
+ * Stop playing.
+ *
+ * @exception std::logic_error if there was no previous call to
+ * start()
+ */
+ virtual void
+ stop(void) throw (std::logic_error);
+
+ /**
+ * Get the length of the currently opened audio clip.
+ * This function waits as long as necessary to get the length.
+ *
+ * @return the length of the currently playing audio clip, or 0,
+ * if nothing is openned.
+ */
+ virtual Ptr::Ref
+ getPlaylength(void) throw ();
+
+ /**
+ * Get the volume of the player.
+ *
+ * @return the volume, from 1 to 100.
+ */
+ virtual unsigned int
+ getVolume(void) throw ();
+
+ /**
+ * Set the volume of the player.
+ *
+ * @param volume the new volume, from 1 to 100.
+ */
+ virtual void
+ setVolume(unsigned int volume) throw ();
+
+ /**
+ * 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
+ * SMIL file at the given URI).
+ * @exception std::logic_error thrown by start() if open() was
+ * unsuccessful, but returned normally (never happens)
+ * @exception std::runtime_error on errors thrown by the helix player
+ */
+ virtual void
+ openAndStart(Ptr::Ref playlist)
+ throw (std::invalid_argument,
+ std::logic_error,
+ std::runtime_error);
+};
+
+
+/* ================================================= external data structures */
+
+
+/* ====================================================== function prototypes */
+
+
+} // namespace PlaylistExecutor
+} // namespace LiveSupport
+
+
+#endif // GstreamerPlayer_h
+
diff --git a/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx b/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx
new file mode 100644
index 000000000..5addb2593
--- /dev/null
+++ b/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx
@@ -0,0 +1,339 @@
+/*------------------------------------------------------------------------------
+
+ Copyright (c) 2004 Media Development Loan Fund
+
+ This file is part of the LiveSupport project.
+ http://livesupport.campware.org/
+ To report bugs, send an e-mail to bugs@campware.org
+
+ LiveSupport is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ LiveSupport 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LiveSupport; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ Author : $Author: maroy $
+ Version : $Revision: 1.1 $
+ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx,v $
+
+------------------------------------------------------------------------------*/
+
+/* ============================================================ include files */
+
+#ifdef HAVE_CONFIG_H
+#include "configure.h"
+#endif
+
+#if HAVE_UNISTD_H
+#include
+#else
+#error "Need unistd.h"
+#endif
+
+
+#include
+#include
+
+#include "LiveSupport/Core/TimeConversion.h"
+
+#include "GstreamerPlayer.h"
+#include "TestEventListener.h"
+#include "GstreamerPlayerTest.h"
+
+
+using namespace LiveSupport::PlaylistExecutor;
+
+/* =================================================== local data structures */
+
+
+/* ================================================ local constants & macros */
+
+CPPUNIT_TEST_SUITE_REGISTRATION(GstreamerPlayerTest);
+
+/**
+ * The name of the configuration file for the Helix player.
+ */
+static const std::string configFileName = "etc/gstreamerPlayer.xml";
+
+
+/* =============================================== local function prototypes */
+
+
+/* ============================================================= module code */
+
+/*------------------------------------------------------------------------------
+ * Set up the test environment
+ *----------------------------------------------------------------------------*/
+void
+GstreamerPlayerTest :: setUp(void) throw ()
+{
+ try {
+ Ptr::Ref parser(
+ new xmlpp::DomParser(configFileName, true));
+ const xmlpp::Document * document = parser->get_document();
+ const xmlpp::Element * root = document->get_root_node();
+
+ player.reset(new GstreamerPlayer());
+ player->configure(*root);
+
+ } catch (std::invalid_argument &e) {
+ std::cerr << "semantic error in configuration file" << std::endl;
+ } catch (xmlpp::exception &e) {
+ std::cerr << e.what() << std::endl;
+ }
+}
+
+
+/*------------------------------------------------------------------------------
+ * Clean up the test environment
+ *----------------------------------------------------------------------------*/
+void
+GstreamerPlayerTest :: tearDown(void) throw ()
+{
+ player.reset();
+}
+
+
+/*------------------------------------------------------------------------------
+ * Test to see if the GstreamerPlayer engine can be started and stopped
+ *----------------------------------------------------------------------------*/
+void
+GstreamerPlayerTest :: firstTest(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ try {
+ player->initialize();
+ CPPUNIT_ASSERT(!player->isPlaying());
+ player->deInitialize();
+ } catch (std::exception &e) {
+ CPPUNIT_FAIL("failed to initialize or de-initialize GstreamerPlayer");
+ }
+}
+
+
+/*------------------------------------------------------------------------------
+ * Play something simple
+ *----------------------------------------------------------------------------*/
+void
+GstreamerPlayerTest :: simplePlayTest(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ Ptr::Ref sleepT(new time_duration(microseconds(10)));
+
+ player->initialize();
+ try {
+ player->open("file:var/test.mp3");
+ } catch (std::invalid_argument &e) {
+ CPPUNIT_FAIL(e.what());
+ }
+ CPPUNIT_ASSERT(!player->isPlaying());
+ player->start();
+ CPPUNIT_ASSERT(player->isPlaying());
+ while (player->isPlaying()) {
+ TimeConversion::sleep(sleepT);
+ }
+
+ Ptr::Ref playlength = player->getPlaylength();
+ CPPUNIT_ASSERT(playlength.get());
+ CPPUNIT_ASSERT(playlength->seconds() == 14);
+ CPPUNIT_ASSERT(playlength->fractional_seconds() == 785187);
+
+ CPPUNIT_ASSERT(!player->isPlaying());
+ player->close();
+ player->deInitialize();
+}
+
+
+/*------------------------------------------------------------------------------
+ * Check for error conditions
+ *----------------------------------------------------------------------------*/
+void
+GstreamerPlayerTest :: checkErrorConditions(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ player->initialize();
+
+ bool gotException;
+
+ CPPUNIT_ASSERT(!player->isPlaying());
+
+ gotException = false;
+ try {
+ player->start();
+ } catch (std::logic_error &e) {
+ gotException = true;
+ }
+ CPPUNIT_ASSERT(gotException);
+
+ gotException = false;
+ try {
+ player->stop();
+ } catch (std::logic_error &e) {
+ gotException = true;
+ }
+ CPPUNIT_ASSERT(gotException);
+
+ gotException = false;
+ try {
+ player->open("totally/bad/URL");
+ } catch (std::invalid_argument &e) {
+ gotException = true;
+ }
+ CPPUNIT_ASSERT(gotException);
+
+ gotException = false;
+ try {
+ player->start();
+ } catch (std::logic_error &e) {
+ gotException = true;
+ }
+ CPPUNIT_ASSERT(gotException);
+
+ // check for opening a wrong URL after opening a proper one
+ try {
+ player->open("file:var/test.mp3");
+ } catch (std::invalid_argument &e) {
+ CPPUNIT_FAIL(e.what());
+ }
+ player->close();
+ gotException = false;
+ try {
+ player->open("totally/bad/URL");
+ } catch (std::invalid_argument &e) {
+ gotException = true;
+ }
+ CPPUNIT_ASSERT(gotException);
+
+ player->deInitialize();
+}
+
+
+/*------------------------------------------------------------------------------
+ * Test to see if attaching and detaching event listeners works.
+ *----------------------------------------------------------------------------*/
+void
+GstreamerPlayerTest :: eventListenerAttachTest(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ CPPUNIT_ASSERT_NO_THROW(player->initialize());
+
+ Ptr::Ref listener1(new TestEventListener());
+ Ptr::Ref listener2(new TestEventListener());
+
+ // try with one listener
+ player->attachListener(listener1.get());
+ CPPUNIT_ASSERT_NO_THROW(
+ player->detachListener(listener1.get())
+ );
+ CPPUNIT_ASSERT_THROW(
+ player->detachListener(listener1.get()),
+ std::invalid_argument
+ );
+
+ // try with two listeners
+ player->attachListener(listener1.get());
+ CPPUNIT_ASSERT_THROW(
+ player->detachListener(listener2.get()),
+ std::invalid_argument
+ );
+ player->attachListener(listener2.get());
+ CPPUNIT_ASSERT_NO_THROW(
+ player->detachListener(listener1.get());
+ );
+
+ player->deInitialize();
+}
+
+
+/*------------------------------------------------------------------------------
+ * Test to see if the player event listener mechanism works.
+ *----------------------------------------------------------------------------*/
+void
+GstreamerPlayerTest :: eventListenerTest(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ CPPUNIT_ASSERT_NO_THROW(player->initialize());
+
+ Ptr::Ref sleepT(new time_duration(microseconds(10)));
+ Ptr::Ref listener1(new TestEventListener());
+ player->attachListener(listener1.get());
+
+ // try with one listener
+ CPPUNIT_ASSERT(!listener1->stopFlag);
+ CPPUNIT_ASSERT_NO_THROW(
+ player->open("file:var/test.mp3");
+ );
+ CPPUNIT_ASSERT(!player->isPlaying());
+ CPPUNIT_ASSERT(!listener1->stopFlag);
+ player->start();
+ CPPUNIT_ASSERT(player->isPlaying());
+ CPPUNIT_ASSERT(!listener1->stopFlag);
+ while (player->isPlaying()) {
+ CPPUNIT_ASSERT(!listener1->stopFlag);
+ TimeConversion::sleep(sleepT);
+ }
+ CPPUNIT_ASSERT(!player->isPlaying());
+ CPPUNIT_ASSERT(listener1->stopFlag);
+ listener1->stopFlag = false;
+
+ // try with two listeners
+ Ptr::Ref listener2(new TestEventListener());
+ player->attachListener(listener2.get());
+
+ CPPUNIT_ASSERT(!listener1->stopFlag);
+ CPPUNIT_ASSERT(!listener2->stopFlag);
+ CPPUNIT_ASSERT_NO_THROW(
+ player->open("file:var/test.mp3");
+ );
+ CPPUNIT_ASSERT(!player->isPlaying());
+ CPPUNIT_ASSERT(!listener1->stopFlag);
+ CPPUNIT_ASSERT(!listener2->stopFlag);
+ player->start();
+ CPPUNIT_ASSERT(player->isPlaying());
+ CPPUNIT_ASSERT(!listener1->stopFlag);
+ CPPUNIT_ASSERT(!listener2->stopFlag);
+ while (player->isPlaying()) {
+ CPPUNIT_ASSERT(!listener1->stopFlag);
+ CPPUNIT_ASSERT(!listener2->stopFlag);
+ TimeConversion::sleep(sleepT);
+ }
+ CPPUNIT_ASSERT(!player->isPlaying());
+ CPPUNIT_ASSERT(listener1->stopFlag);
+ CPPUNIT_ASSERT(listener2->stopFlag);
+ listener1->stopFlag = false;
+ listener2->stopFlag = false;
+
+ // try with only the second listener
+ CPPUNIT_ASSERT_NO_THROW(
+ player->detachListener(listener1.get());
+ );
+ CPPUNIT_ASSERT(!listener2->stopFlag);
+ CPPUNIT_ASSERT_NO_THROW(
+ player->open("file:var/test.mp3");
+ );
+ CPPUNIT_ASSERT(!player->isPlaying());
+ CPPUNIT_ASSERT(!listener2->stopFlag);
+ player->start();
+ CPPUNIT_ASSERT(player->isPlaying());
+ CPPUNIT_ASSERT(!listener2->stopFlag);
+ while (player->isPlaying()) {
+ CPPUNIT_ASSERT(!listener2->stopFlag);
+ TimeConversion::sleep(sleepT);
+ }
+ CPPUNIT_ASSERT(!player->isPlaying());
+ CPPUNIT_ASSERT(listener2->stopFlag);
+ listener2->stopFlag = false;
+
+ player->close();
+ player->deInitialize();
+}
+
diff --git a/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h b/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h
new file mode 100644
index 000000000..ca202df50
--- /dev/null
+++ b/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h
@@ -0,0 +1,151 @@
+/*------------------------------------------------------------------------------
+
+ Copyright (c) 2004 Media Development Loan Fund
+
+ This file is part of the LiveSupport project.
+ http://livesupport.campware.org/
+ To report bugs, send an e-mail to bugs@campware.org
+
+ LiveSupport is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ LiveSupport 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LiveSupport; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ Author : $Author: maroy $
+ Version : $Revision: 1.1 $
+ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h,v $
+
+------------------------------------------------------------------------------*/
+#ifndef GstreamerPlayerTest_h
+#define GstreamerPlayerTest_h
+
+#ifndef __cplusplus
+#error This is a C++ include file
+#endif
+
+
+/* ============================================================ include files */
+
+#ifdef HAVE_CONFIG_H
+#include "configure.h"
+#endif
+
+#include
+
+
+namespace LiveSupport {
+namespace PlaylistExecutor {
+
+/* ================================================================ constants */
+
+
+/* =================================================================== macros */
+
+
+/* =============================================================== data types */
+
+/**
+ * Unit test for the GstreamerPlayer class.
+ *
+ * @author $Author: maroy $
+ * @version $Revision: 1.1 $
+ * @see GstreamerPlayer
+ */
+class GstreamerPlayerTest : public CPPUNIT_NS::TestFixture
+{
+ CPPUNIT_TEST_SUITE(GstreamerPlayerTest);
+ CPPUNIT_TEST(firstTest);
+ CPPUNIT_TEST(simplePlayTest);
+ CPPUNIT_TEST(checkErrorConditions);
+ CPPUNIT_TEST(eventListenerAttachTest);
+ CPPUNIT_TEST(eventListenerTest);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+
+ /**
+ * The player to use for the tests.
+ */
+ Ptr::Ref player;
+
+
+ protected:
+
+ /**
+ * A simple test.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ firstTest(void) throw (CPPUNIT_NS::Exception);
+
+ /**
+ * A simple play test.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ simplePlayTest(void) throw (CPPUNIT_NS::Exception);
+
+ /**
+ * Check for error conditions.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ checkErrorConditions(void) throw (CPPUNIT_NS::Exception);
+
+ /**
+ * Test to see if attaching and detaching event listeners works.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ eventListenerAttachTest(void) throw (CPPUNIT_NS::Exception);
+
+ /**
+ * Test to see if the player event listener mechanism works.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ eventListenerTest(void) throw (CPPUNIT_NS::Exception);
+
+
+ public:
+
+ /**
+ * Set up the environment for the test case.
+ */
+ void
+ setUp(void) throw ();
+
+ /**
+ * Clean up the environment after the test case.
+ */
+ void
+ tearDown(void) throw ();
+};
+
+
+/* ================================================= external data structures */
+
+
+/* ====================================================== function prototypes */
+
+
+} // namespace PlaylistExecutor
+} // namespace LiveSupport
+
+#endif // GstreamerPlayerTest_h
+
diff --git a/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.cxx b/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.cxx
new file mode 100644
index 000000000..c9f57424c
--- /dev/null
+++ b/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.cxx
@@ -0,0 +1,247 @@
+/*------------------------------------------------------------------------------
+
+ Copyright (c) 2004 Media Development Loan Fund
+
+ This file is part of the LiveSupport project.
+ http://livesupport.campware.org/
+ To report bugs, send an e-mail to bugs@campware.org
+
+ LiveSupport is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ LiveSupport 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LiveSupport; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ Author : $Author: maroy $
+ Version : $Revision: 1.1 $
+ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.cxx,v $
+
+------------------------------------------------------------------------------*/
+
+/* ============================================================ include files */
+
+#ifdef HAVE_CONFIG_H
+#include "configure.h"
+#endif
+
+#if HAVE_UNISTD_H
+#include
+#else
+#error "Need unistd.h"
+#endif
+
+
+#include
+#include
+
+#include "LiveSupport/Core/TimeConversion.h"
+
+#include "GstreamerPlayer.h"
+#include "TestEventListener.h"
+#include "TwoGstreamerPlayersTest.h"
+
+
+using namespace LiveSupport::PlaylistExecutor;
+
+/* =================================================== local data structures */
+
+
+/* ================================================ local constants & macros */
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TwoGstreamerPlayersTest);
+
+/**
+ * The name of the configuration file for the Helix player.
+ */
+static const std::string configFileName = "etc/twoGstreamerPlayers.xml";
+
+/**
+ * The name of the root XML element in the configuration file.
+ */
+static const std::string rootElementName = "twoGstreamerPlayers";
+
+
+/* =============================================== local function prototypes */
+
+
+/* ============================================================= module code */
+
+/*------------------------------------------------------------------------------
+ * Set up the test environment
+ *----------------------------------------------------------------------------*/
+void
+TwoGstreamerPlayersTest :: setUp(void) throw ()
+{
+ try {
+ Ptr::Ref parser(
+ new xmlpp::DomParser(configFileName, true));
+ const xmlpp::Document * document = parser->get_document();
+ const xmlpp::Element * root = document->get_root_node();
+
+ xmlpp::Node::NodeList children;
+ const xmlpp::Element * element;
+
+ children = root->get_children(GstreamerPlayer::getConfigElementName());
+
+ element = dynamic_cast (*(children.begin()));
+ player1.reset(new GstreamerPlayer());
+ player1->configure(*element);
+
+ children.pop_front();
+ element = dynamic_cast (*(children.begin()));
+ player2.reset(new GstreamerPlayer());
+ player2->configure(*element);
+
+ } catch (std::invalid_argument &e) {
+ std::cerr << "semantic error in configuration file" << std::endl;
+ } catch (xmlpp::exception &e) {
+ std::cerr << e.what() << std::endl;
+ }
+}
+
+
+/*------------------------------------------------------------------------------
+ * Clean up the test environment
+ *----------------------------------------------------------------------------*/
+void
+TwoGstreamerPlayersTest :: tearDown(void) throw ()
+{
+ player2.reset();
+ player1.reset();
+}
+
+
+/*------------------------------------------------------------------------------
+ * Test to see if the GstreamerPlayer engine can be started and stopped
+ *----------------------------------------------------------------------------*/
+void
+TwoGstreamerPlayersTest :: firstTest(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ try {
+ player1->initialize();
+ player2->initialize();
+ CPPUNIT_ASSERT(!player1->isPlaying());
+ CPPUNIT_ASSERT(!player2->isPlaying());
+ player2->deInitialize();
+ player1->deInitialize();
+ } catch (std::exception &e) {
+ CPPUNIT_FAIL("failed to initialize or de-initialize GstreamerPlayer");
+ }
+}
+
+
+/*------------------------------------------------------------------------------
+ * Play something simple on player #1
+ *----------------------------------------------------------------------------*/
+void
+TwoGstreamerPlayersTest :: simplePlay1Test(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ Ptr::Ref sleepT(new time_duration(microseconds(10)));
+
+ player1->initialize();
+ try {
+ player1->open("file:var/test10001.mp3");
+ } catch (std::invalid_argument &e) {
+ CPPUNIT_FAIL(e.what());
+ }
+ CPPUNIT_ASSERT(!player1->isPlaying());
+ player1->start();
+ CPPUNIT_ASSERT(player1->isPlaying());
+ while (player1->isPlaying()) {
+ TimeConversion::sleep(sleepT);
+ }
+ CPPUNIT_ASSERT(!player1->isPlaying());
+ player1->close();
+ player1->deInitialize();
+}
+
+
+/*------------------------------------------------------------------------------
+ * Play something simple on player #2
+ *----------------------------------------------------------------------------*/
+void
+TwoGstreamerPlayersTest :: simplePlay2Test(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ Ptr::Ref sleepT(new time_duration(microseconds(10)));
+
+ player2->initialize();
+ try {
+ player2->open("file:var/test.mp3");
+ } catch (std::invalid_argument &e) {
+ CPPUNIT_FAIL(e.what());
+ }
+ CPPUNIT_ASSERT(!player2->isPlaying());
+ player2->start();
+ CPPUNIT_ASSERT(player2->isPlaying());
+ while (player2->isPlaying()) {
+ TimeConversion::sleep(sleepT);
+ }
+ CPPUNIT_ASSERT(!player2->isPlaying());
+ player2->close();
+ player2->deInitialize();
+}
+
+
+/*------------------------------------------------------------------------------
+ * Play something simple on both players
+ *----------------------------------------------------------------------------*/
+void
+TwoGstreamerPlayersTest :: playBothTest(void)
+ throw (CPPUNIT_NS::Exception)
+{
+ Ptr::Ref sleepT(new time_duration(microseconds(10)));
+
+ player1->initialize();
+ player2->initialize();
+
+ // start playing on player1
+ try {
+ player1->open("file:var/test10001.mp3");
+ } catch (std::invalid_argument &e) {
+ CPPUNIT_FAIL(e.what());
+ }
+ CPPUNIT_ASSERT(!player1->isPlaying());
+ player1->start();
+ CPPUNIT_ASSERT(player1->isPlaying());
+
+ // sleep some time
+ for (unsigned i = 0; i < 100; ++i) {
+ TimeConversion::sleep(sleepT);
+ }
+
+ // start playing on player2
+ try {
+ player2->open("file:var/test.mp3");
+ } catch (std::invalid_argument &e) {
+ CPPUNIT_FAIL(e.what());
+ }
+ CPPUNIT_ASSERT(!player2->isPlaying());
+ player2->start();
+ CPPUNIT_ASSERT(player2->isPlaying());
+
+ // wait for both players to finish
+ while (player1->isPlaying() || player2->isPlaying()) {
+ TimeConversion::sleep(sleepT);
+ }
+ CPPUNIT_ASSERT(!player1->isPlaying());
+ CPPUNIT_ASSERT(!player2->isPlaying());
+
+ player2->close();
+ player1->close();
+ player2->deInitialize();
+ player1->deInitialize();
+}
+
+
diff --git a/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.h b/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.h
new file mode 100644
index 000000000..b137d8831
--- /dev/null
+++ b/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.h
@@ -0,0 +1,161 @@
+/*------------------------------------------------------------------------------
+
+ Copyright (c) 2004 Media Development Loan Fund
+
+ This file is part of the LiveSupport project.
+ http://livesupport.campware.org/
+ To report bugs, send an e-mail to bugs@campware.org
+
+ LiveSupport is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ LiveSupport 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LiveSupport; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ Author : $Author: maroy $
+ Version : $Revision: 1.1 $
+ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.h,v $
+
+------------------------------------------------------------------------------*/
+#ifndef TwoGstreamerPlayersTest_h
+#define TwoGstreamerPlayersTest_h
+
+#ifndef __cplusplus
+#error This is a C++ include file
+#endif
+
+
+/* ============================================================ include files */
+
+#ifdef HAVE_CONFIG_H
+#include "configure.h"
+#endif
+
+#include
+
+
+namespace LiveSupport {
+namespace PlaylistExecutor {
+
+/* ================================================================ constants */
+
+
+/* =================================================================== macros */
+
+
+/* =============================================================== data types */
+
+/**
+ * Unit test for the GstreamerPlayer class, two see if two helix players,
+ * playing on two different sound cards work correctly.
+ *
+ * @author $Author: maroy $
+ * @version $Revision: 1.1 $
+ * @see GstreamerPlayer
+ */
+class TwoGstreamerPlayersTest : public CPPUNIT_NS::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TwoGstreamerPlayersTest);
+ CPPUNIT_TEST(firstTest);
+ CPPUNIT_TEST(simplePlay1Test);
+ CPPUNIT_TEST(simplePlay2Test);
+ CPPUNIT_TEST(playBothTest);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+
+ /**
+ * Helix player #1 to use for the tests.
+ */
+ Ptr::Ref player1;
+
+ /**
+ * Helix player #2 to use for the tests.
+ */
+ Ptr::Ref player2;
+
+ /**
+ * Play a specific file.
+ *
+ * @param fileName the name of the file to play.
+ * @param player the player to use for playing the file.
+ * @exception CPPUNIT_NS::Exception on playing failures
+ */
+ void
+ playFile(const std::string & fileName,
+ Ptr::Ref player)
+ throw (CPPUNIT_NS::Exception);
+
+
+ protected:
+
+ /**
+ * A simple test.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ firstTest(void) throw (CPPUNIT_NS::Exception);
+
+
+ /**
+ * Play something on player #1.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ simplePlay1Test(void) throw (CPPUNIT_NS::Exception);
+
+ /**
+ * Play something on player #2.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ simplePlay2Test(void) throw (CPPUNIT_NS::Exception);
+
+ /**
+ * Play something on both players, at the same time.
+ *
+ * @exception CPPUNIT_NS::Exception on test failures.
+ */
+ void
+ playBothTest(void) throw (CPPUNIT_NS::Exception);
+
+
+ public:
+
+ /**
+ * Set up the environment for the test case.
+ */
+ void
+ setUp(void) throw ();
+
+ /**
+ * Clean up the environment after the test case.
+ */
+ void
+ tearDown(void) throw ();
+};
+
+
+/* ================================================= external data structures */
+
+
+/* ====================================================== function prototypes */
+
+
+} // namespace PlaylistExecutor
+} // namespace LiveSupport
+
+#endif // TwoGstreamerPlayersTest_h
+